package com.jinzhi.jinzhidata.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jinzhi.jinzhidata.pojo.WX.message.ImageMessage;
import com.jinzhi.jinzhidata.pojo.WX.message.NewsMessage;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * @author vansl
 * @description
 * @date 2020-01-09 20:45
 **/
public class WeChatMessageUtil {

    /**
     * 验证签名
     *
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static boolean checkSignature(String signature, String timestamp, String nonce) {
        String[] arr = new String[]{Constant.TOKEN, timestamp, nonce};
        // 将token、timestamp、nonce三个参数进行字典序排序
        //Arrays.sort(arr);
        sort(arr);
        StringBuilder content = new StringBuilder();
        for (String s : arr) {
            content.append(s);
        }
        MessageDigest md = null;
        String tmpStr = null;

        try {
            md = MessageDigest.getInstance("SHA-1");
            // 将三个参数字符串拼接成一个字符串进行sha1加密
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        content = null;
        // 将sha1加密后的字符串可与signature对比，标识该请求来源于微信
        return tmpStr != null && tmpStr.equals(signature.toUpperCase());
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param byteArray
     * @return
     */
    private static String byteToStr(byte[] byteArray) {
        StringBuilder strDigest = new StringBuilder();
        for (byte b : byteArray) {
            strDigest.append(byteToHexStr(b));
        }
        return strDigest.toString();
    }

    /**
     * 将字节转换为十六进制字符串
     *
     * @param mByte
     * @return
     */
    private static String byteToHexStr(byte mByte) {
        char[] digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
                'B', 'C', 'D', 'E', 'F'};
        char[] tempArr = new char[2];
        tempArr[0] = digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = digit[mByte & 0X0F];

        return new String(tempArr);
    }

    public static void sort(String[] a) {
        for (int i = 0; i < a.length - 1; i++) {
            for (int j = i + 1; j < a.length; j++) {
                if (a[j].compareTo(a[i]) < 0) {
                    String temp = a[i];
                    a[i] = a[j];
                    a[j] = temp;
                }
            }
        }
    }

    /**
     * 解析微信发来的请求(xml)
     *
     * @param request
     * @return
     * @throws Exception
     */
    @SuppressWarnings({"unchecked"})
    public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
        // 将解析结果存储在HashMap中
        Map<String, String> map = new HashMap<String, String>();

        // 从request中取得输入流
        InputStream inputStream = request.getInputStream();
        // 读取输入流
        SAXReader reader = new SAXReader();
        Document document = reader.read(inputStream);
        // 得到xml根元素
        Element root = document.getRootElement();
        // 得到根元素的所有子节点
        List<Element> elementList = root.elements();
        // 遍历所有子节点
        for (Element e : elementList) {
            map.put(e.getName(), e.getText());
        }

        // 释放资源
        inputStream.close();
        inputStream = null;
        return map;
    }

    public static String mapToXML(Map map) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        mapToXML2(map, sb);
        sb.append("</xml>");
        try {
            return sb.toString();
        } catch (Exception e) {
        }
        return null;
    }

    private static void mapToXML2(Map map, StringBuffer sb) {
        Set set = map.keySet();
        for (Iterator it = set.iterator(); it.hasNext(); ) {
            String key = (String) it.next();
            Object value = map.get(key);
            if (null == value) {
                value = "";
            }
            if (value.getClass().getName().equals("java.util.ArrayList")) {
                ArrayList list = (ArrayList) map.get(key);
                sb.append("<" + key + ">");
                for (int i = 0; i < list.size(); i++) {
                    HashMap hm = (HashMap) list.get(i);
                    mapToXML2(hm, sb);
                }
                sb.append("</" + key + ">");

            } else {
                if (value instanceof HashMap) {
                    sb.append("<" + key + ">");
                    mapToXML2((HashMap) value, sb);
                    sb.append("</" + key + ">");
                } else {
                    sb.append("<" + key + "><![CDATA[" + value + "]]></" + key + ">");
                }

            }

        }
    }

    /**
     * 回复文本消息
     *
     * @param requestMap
     * @param content
     * @return
     */
    public static String sendTextMsg(Map<String, String> requestMap, String content) {

        Map<String, Object> map = new HashMap<>();
        map.put("ToUserName", requestMap.get(Constant.FromUserName));
        map.put("FromUserName", requestMap.get(Constant.ToUserName));
        map.put("MsgType", "text");
        map.put("CreateTime", System.currentTimeMillis());
        map.put("Content", content);
        return mapToXML(map);
    }

    /**
     * 回复图片消息
     *
     * @param requestMap
     * @param mediaId
     * @return
     */
    public static String sendImageMsg(Map<String, String> requestMap, String mediaId) {
        Map<String, Object> map = new HashMap<>();
        map.put("ToUserName", requestMap.get(Constant.FromUserName));
        map.put("FromUserName", requestMap.get(Constant.ToUserName));
        map.put("MsgType", "image");
        map.put("CreateTime", System.currentTimeMillis());
        ImageMessage imageMessage = new ImageMessage();
        imageMessage.setMediaId(mediaId);
        map.put("Image", imageMessage);
        return mapToXML(map);
    }


    /**
     * 回复图文消息
     *
     * @param requestMap
     * @param NewsMessages
     * @return
     */
    public static String sendNewsMsg(Map<String, String> requestMap, List<NewsMessage> NewsMessages) {
        if (NewsMessages == null || NewsMessages.size() < 1) {
            return "";
        }
        Map<String, Object> map = new HashMap<>();
        map.put("ToUserName", requestMap.get(Constant.FromUserName));
        map.put("FromUserName", requestMap.get(Constant.ToUserName));
        map.put("MsgType", "news");
        map.put("CreateTime", System.currentTimeMillis());
        List<Map<String, Object>> articles = new ArrayList<>();
        for (NewsMessage message : NewsMessages) {
            Map<String, Object> item = new HashMap<>();
            Map<String, Object> itemContent = new HashMap<String, Object>();
            itemContent.put("Title", message.getTitle());
            itemContent.put("Description", message.getDescription());
            itemContent.put("PicUrl", message.getPicUrl());
            itemContent.put("Url", message.getUrl());
            item.put("item", itemContent);
            articles.add(item);
        }
        map.put("Articles", articles);
        map.put("ArticleCount", articles.size());
        return mapToXML(map);
    }


    public static String getAccessToken() {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + Constant.WX_APPID + "&secret=" + Constant.WX_SECRET;
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(GET_ACCESS_TOKEN_URL, String.class);
        JSONObject response = JSON.parseObject(responseEntity.getBody());
        return (String) response.get("access_token");
    }

    public static JSONObject getUserInfo(String accessToken, String openid) {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        String GET_USER_INFO_URL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + accessToken + "&openid=" + openid;
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(GET_USER_INFO_URL, String.class);
        System.out.println(responseEntity.getBody());
        return JSON.parseObject(responseEntity.getBody());
    }

    public static String getQRCode(String accessToken, String sceneId) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("expire_seconds", 2592000);
        jsonObject.put("action_name", Constant.QR_STR_SCENE);
        JSONObject actionInfo = new JSONObject();
        JSONObject scene = new JSONObject();
        scene.put("scene_str", sceneId);
        actionInfo.put("scene", scene);
        jsonObject.put("action_info", actionInfo);
        String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken;
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, jsonObject, String.class);
        JSONObject response = JSON.parseObject(responseEntity.getBody());
        System.out.println(response);
        String ticket = response.getString("ticket");
        return "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + ticket;
    }
}
